import java.awt.*;
import java.awt.event.*;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;

import javax.swing.*;

/**
 * Graphical user interface to a Tic Tac Toe application. The GUI is incomplete
 * because it has no associated player. It also needs a routine for checking if
 * one of the players have got five marks in a row.
 */
public class TicTacToeGui extends JFrame implements Constants, ActionListener {
	/** Textfield showing what mark you use ('X' or 'O') */
	private JTextField id;
	/** TextArea giving feedback to the user */
	private static TextArea display;
	/** The panel containing the board */
	private JPanel boardPanel;
	/** The squares of the board */
	private Square board[][];// row, col
	/** The menu bar */
	private JMenuBar menuBar;
	/** The game submenu */
	private JMenu gameMenu;
	/** Game submenu choices */
	private JMenuItem newGameItem, quitItem;
	private boolean myTurn = true;

	/** The name of the player using this GUI */
	private String myName;
	/** The mark used by this player ('X' or 'O') */
	private char myMark;
	private static MailboxSkeleton serverBox;

	/**
	 * Creates a new GUI.
	 * 
	 * @param name
	 *            The name of that player.
	 * @param mark
	 *            The mark used by that player.
	 */
	public TicTacToeGui(String name, char mark) {
		myName = name;
		myMark = mark;
		// Create GUI components:
		// The display at the bottom:
		display = new TextArea("", 4, 30, TextArea.SCROLLBARS_VERTICAL_ONLY);
		display.setEditable(false);
		// The name field at the top:
		id = new JTextField();
		id.setEditable(false);
		id.setText(myName + ": You are player " + getMyMark());
		// The board:
		JPanel gridPanel = new JPanel();
		gridPanel.setLayout(new GridLayout(BOARD_SIZE, BOARD_SIZE, 0, 0));
		board = new Square[BOARD_SIZE][BOARD_SIZE];
		for (int row = 0; row < board.length; row++)
			for (int col = 0; col < board[row].length; col++) {
				board[row][col] = new Square(this, row, col);
				gridPanel.add(board[row][col]);
			}
		boardPanel = new JPanel();
		boardPanel.add(gridPanel);

		// Place the components:
		Container cp = getContentPane();
		cp.setLayout(new BorderLayout());
		cp.add("South", display);
		cp.add("North", id);
		cp.add("Center", boardPanel);

		// Create the menu.
		menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		gameMenu = new JMenu("Game");
		gameMenu.setMnemonic(KeyEvent.VK_G);
		menuBar.add(gameMenu);
		newGameItem = new JMenuItem("New game", KeyEvent.VK_N);
		newGameItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0));
		gameMenu.add(newGameItem);
		quitItem = new JMenuItem("Quit", KeyEvent.VK_Q);
		quitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4,
				ActionEvent.ALT_MASK));
		gameMenu.add(quitItem);

		// Add listeners
		newGameItem.addActionListener(this);
		quitItem.addActionListener(this);
		// Add an anonymous WindowListener which calls quit() when the window is
		// closing
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				quit();
			}
		});

		// Place and show the window:
		setTitle("Tic Tac Toe: " + name);
		setSize(WIN_WIDTH, WIN_HEIGHT);
		setLocation(200, 200);
		setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		setVisible(true);
	}

	/**
	 * Called by the Square class when an empty square is clicked.
	 * 
	 * @param row
	 *            The row of the square that was clicked.
	 * @param column
	 *            The column of the square that was clicked.
	 */
	public void squareClicked(int row, int column) {
		
		if (myTurn) {
			setMark(row, column, getMyMark());
			try {
				serverBox.setMark(row, column);
				serverBox.yieldTurn();
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			myTurn = false;
		} else {
			display.setText("Not your turn!");
		}

	}

	protected char winner() {
		// Checking rows
		char current = ' ';
		for (int i = 0; i < WINNER_LENGTH; i++) {
			int i1 = 0;
			for (i1 = 0; i1 < WINNER_LENGTH; i1++) {
				if (!Character.isLetter(board[i][i1].getMark())) {
					break;
				}
				if (i1 == 0) {
					current = board[i][i1].getMark();
				} else if (current != board[i][i1].getMark()) {
					break;
				}
				if (i1 == 4) {
					// Found winner
					return current;
				}
			}
		}
		// Checking columns
		for (int i = 0; i < WINNER_LENGTH; i++) {
			current = ' ';
			int i1 = 0;
			for (i1 = 0; i1 < WINNER_LENGTH; i1++) {
				if (!Character.isLetter(board[i1][i].getMark())) {
					break;
				}
				if (i1 == 0) {
					current = board[i1][i].getMark();
				} else if (current != board[i1][i].getMark()) {
					break;
				}
				if (i1 == 4) {
					// Found winner
					return current;
				}
			}
		}

		// Checking diagonals
		current = board[0][0].getMark();
		if (Character.isLetter(current) && board[1][1].getMark() == current
				&& board[2][2].getMark() == current) {
			return current;
		}
		current = board[2][0].getMark();
		if (Character.isLetter(current) && board[1][1].getMark() == current
				&& board[0][2].getMark() == current) {
			return current;
		}
		return '!';
	}

	/**
	 * Marks the specified square of the board with the specified mark.
	 * 
	 * @param row
	 *            The row of the square to mark.
	 * @param column
	 *            The column of the square to mark.
	 * @param mark
	 *            The mark to use.
	 */
	public void setMark(int row, int column, char mark) {
		board[row][column].setMark(mark);
		repaint();
		char theWinner = winner();
		if (theWinner != '!') {
			display.setText(theWinner+" wins");
			JOptionPane.showMessageDialog(null, theWinner+" wins");
			
		}
	}

	/**
	 * Called when a menu item has been selected.
	 * 
	 * @param e
	 *            The ActionEvent that occured.
	 */
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == newGameItem)
			newGame();
		else if (e.getSource() == quitItem)
			quit();
	}

	/**
	 * Starts a new game, if the user confirms it in a dialog box.
	 */
	public void newGame() {
		// This method must be modified!
		if (JOptionPane.showConfirmDialog(this,
				"Are you sure you want to start a new game?", "Start over?",
				JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
			clearBoard();
		}
	}

	/**
	 * Removes all marks from the board.
	 */
	public void clearBoard() {
		for (int row = 0; row < board.length; row++)
			for (int col = 0; col < board[row].length; col++)
				board[row][col].setMark(' ');
		repaint();
	}

	/**
	 * Exits the game, if the user confirms it in a dialog box. Should notify
	 * the opponent that we left the game.
	 */
	public void quit() {
		// This method should be modified!
		if (JOptionPane.showConfirmDialog(this,
				"Are you sure you want to quit?", "Really quit?",
				JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
			System.exit(0);
		}
	}

	/**
	 * Outputs a message to the user.
	 * 
	 * @param s
	 *            The string to display. Adds a newline to the end of the
	 *            string.
	 */
	public void println(String s) {
		display.append(s + "\n");
	}

	/**
	 * Outputs a message to the user.
	 * 
	 * @param s
	 *            The string to display.
	 */
	public void print(String s) {
		display.append(s);
	}

	/**
	 * Starts up a GUI without an associated player, in order to check the
	 * appearance of the GUI.
	 */
	public static void main(String args[]) throws Exception {
		System.setSecurityManager(new LiberalSecurityManager());
		// RmiServer rmiServer = new RmiServ

		String playerName = JOptionPane.showInputDialog(null,
				"Either 'X' or 'O'").toUpperCase();
		char myMark = playerName.charAt(0);
		TicTacToeGui myGui = new TicTacToeGui(playerName, playerName.charAt(0));

		char otherMark;
		if (myMark == 'X') {
			otherMark = 'O';
		} else {
			otherMark = 'X';
		}

		playerName = "player" + myMark; // this part is confusing to us too!

		// System.out.println("" + LocateRegistry.getRegistry(1099));

		try {
			LocateRegistry.createRegistry(1099);
		} catch (java.rmi.server.ExportException e) {
			// Registry already exists on port
		}

		MailboxSkeleton mailbox = new Mailbox(playerName, myGui);

		Naming.rebind("rmi://localhost/" + playerName, mailbox);

		String buddyUrl = "rmi://localhost:1099/" + "player" + otherMark;

		// TODO: Set up my tent/mailbox in the cloud/campingplace

		// Loop while looking for a buddy's (remote) mailbox 
		// "Buddy lookup loop"
		while (serverBox == null) {
			try {
				serverBox = (MailboxSkeleton) Naming.lookup(buddyUrl);

			} catch (NotBoundException e) {
				Thread.sleep(100);
			}
			display.setText("I am looking for a partner\n");
		}
		display.setText("Partner found");

	}

	public char getMyMark() {
		return myMark;
	}

	public char getOtherMark() {

		return (myMark == 'X') ? 'O' : 'X';

	}
	
	public void setTurn(){
		myTurn = true;
	}

}
